﻿using Newtonsoft.Json.Linq;
using SAP.BusinessOne.Mackinac.Generator.Model;
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;

namespace SAP.BusinessOne.Mackinac.Generator.Engine
{
    class MackinacBuilder
    {
        private MBag _bag = new MBag();

        public dynamic ToDynamicBag()
        {
            return _bag;
        }

        public MackinacBuilder PutTarget(Assembly assembly)
        {
            var fi = new FileInfo(assembly.Location);
            _bag.AssemblyName = fi.Name;

            var ns = Encapsulate(assembly);
            _bag.Namespaces = ns;

            _bag.Checksum = CalcSha1(ns);

            return this;
        }

        private string CalcSha1(object obj)
        {
            var raw = JToken.FromObject(obj).ToString(Newtonsoft.Json.Formatting.None);
            var data = Encoding.UTF8.GetBytes(raw);

            var sha = new SHA1Managed();
            byte[] checksum = sha.ComputeHash(data, 0, data.Length);
            string bin = BitConverter.ToString(checksum).Replace("-", string.Empty);
            return bin;
        }

        private IEnumerable<IGrouping<Namespace, Clazz>> Encapsulate(Assembly assembly)
        {
            // get all types and contracts
            var types = new Dictionary<Type, Type>();
            var typeList = assembly.GetTypes().Where(p => p.GetCustomAttributes(typeof(ExportAttribute), false).Any());
            foreach (var type in typeList)
            {
                var export = type.GetCustomAttributes(typeof(ExportAttribute), false).First() as ExportAttribute;
                var contract = export.ContractType;
                types.Add(type, contract);
            }

            var clzList = new List<Clazz>();
            foreach (var pair in types)
            {
                clzList.Add(new Clazz(pair.Key, pair.Value));
            }

            var source = clzList.GroupBy(p => p.NS);

            var ss = source.ToArray();
            return ss;
        }
    }
}
